package com.juneng.quartz;

import com.alibaba.druid.pool.DruidDataSource;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 类ConfigProperties.java的实现描述：配置
 *
 * @author 吴昊 2017年5月8日 下午3:45:12
 */
@Component
public class QuartzConfigProperties {

    @Value("${spring.quartz.scheduler.instanceName}")
    private String  quartzInstanceName;
    @Value("${spring.quartz.scheduler.instanceId}")
    private String  instanceId;
    @Value("${spring.quartz.scheduler.skipUpdateCheck}")
    private String  skipUpdateCheck;
    @Value("${spring.quartz.scheduler.jmx.export}")
    private String  export;

    @Value("${spring.quartz.threadPool.class}")
    private String  threadPoolClass;
    @Value("${spring.quartz.threadPool.threadCount}")
    private String  threadCount;
    @Value("${spring.quartz.threadPool.threadPriority}")
    private String  threadPriority;
    @Value("${spring.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread}")
    private String  threadsInheritContextClassLoaderOfInitializingThread;

    @Value("${spring.quartz.jobStore.misfireThreshold}")
    private String  misfireThreshold;
    @Value("${spring.quartz.jobStore.class}")
    private String  jobStoreClass;
    @Value("${spring.quartz.jobStore.tablePrefix}")
    private String  tablePrefix;
    @Value("${spring.quartz.jobStore.dataSource}")
    private String  dataSource;
    @Value("${spring.quartz.jobStore.isClustered}")
    private String  isClustered;
    @Value("${spring.quartz.jobStore.clusterCheckinInterval}")
    private String  clusterCheckinInterval;
    @Value("${spring.quartz.jobStore.driverDelegateClass}")
    private String  driverDelegateClass;
    @Value("${spring.quartz.jobStore.maxMisfiresToHandleAtATime}")
    private String  maxMisfiresToHandleAtATime;
    @Value("${spring.quartz.jobStore.txIsolationLevelSerializable}")
    private String  txIsolationLevelSerializable;
    @Value("${spring.quartz.jobStore.selectWithLockSQL}")
    private String  selectWithLockSQL;

    @Value("${spring.quartz.plugin.triggHistory.class}")
    private String  triggHistoryClass;
    @Value("${spring.quartz.plugin.shutdownhook.class}")
    private String  shutdownhookClass;
    @Value("${spring.quartz.plugin.shutdownhook.cleanShutdown}")
    private String  cleanShutdown;

    @Value("${spring.quartz.dataSource.myDS.driver}")
    private String  driver;
    @Value("${spring.quartz.dataSource.myDS.URL}")
    private String  URL;
    @Value("${spring.quartz.dataSource.myDS.user}")
    private String  user;
    @Value("${spring.quartz.dataSource.myDS.password}")
    private String  password;
    @Value("${spring.quartz.dataSource.myDS.maxConnections}")
    private String  maxConnections;
    @Value("${spring.quartz.dataSource.myDS.max-active}")
    private int     maxActive;
    @Value("${spring.quartz.dataSource.myDS.min-idle}")
    private int     minIdle;
    @Value("${spring.quartz.dataSource.myDS.initial-size}")
    private int     initialSize;
    @Value("${spring.quartz.dataSource.myDS.test-on-borrow}")
    private boolean testOnBorrow;

    /**
     * 设置属性
     *
     * @return
     * @throws IOException
     */
    private Properties quartzProperties() throws IOException {
        Properties prop = new Properties();
        prop.put("quartz.scheduler.instanceName", quartzInstanceName);
        prop.put("spring.quartz.scheduler.instanceId", instanceId);
        prop.put("spring.quartz.scheduler.skipUpdateCheck", skipUpdateCheck);
        prop.put("spring.quartz.scheduler.jmx.export", export);

        prop.put("spring.quartz.jobStore.class", jobStoreClass);
        prop.put("spring.quartz.jobStore.driverDelegateClass", driverDelegateClass);
        prop.put("spring.quartz.jobStore.dataSource", dataSource);
        prop.put("spring.quartz.jobStore.tablePrefix", tablePrefix);
        prop.put("spring.quartz.jobStore.isClustered", isClustered);
        prop.put("spring.quartz.jobStore.clusterCheckinInterval", clusterCheckinInterval);
        prop.put("spring.quartz.jobStore.maxMisfiresToHandleAtATime", maxMisfiresToHandleAtATime);
        prop.put("spring.quartz.jobStore.misfireThreshold", misfireThreshold);
        prop.put("spring.quartz.jobStore.txIsolationLevelSerializable", txIsolationLevelSerializable);
        prop.put("spring.quartz.jobStore.selectWithLockSQL", selectWithLockSQL);

        prop.put("spring.quartz.threadPool.class", threadPoolClass);
        prop.put("spring.quartz.threadPool.threadCount", threadCount);
        prop.put("spring.quartz.threadPool.threadPriority", threadPriority);
        prop.put("spring.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread",
                 threadsInheritContextClassLoaderOfInitializingThread);

        prop.put("spring.quartz.dataSource.myDS.driver", driver);
        prop.put("spring.quartz.dataSource.myDS.URL", URL);
        prop.put("spring.quartz.dataSource.myDS.user", user);
        prop.put("spring.quartz.dataSource.myDS.password", password);
        prop.put("spring.quartz.dataSource.myDS.maxConnections", maxConnections);

        prop.put("spring.quartz.plugin.triggHistory.class", triggHistoryClass);
        prop.put("spring.quartz.plugin.shutdownhook.class", shutdownhookClass);
        prop.put("spring.quartz.plugin.shutdownhook.cleanShutdown", cleanShutdown);

        return prop;
    }

    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.secondary")
    public DataSource dataSourceQuartz() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(URL);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        if (initialSize > 0) {
            dataSource.setInitialSize(initialSize);
        }
        if (minIdle > 0) {
            dataSource.setMinIdle(minIdle);
        }
        if (maxActive > 0) {
            dataSource.setMaxActive(maxActive);
        }
        dataSource.setTestOnBorrow(testOnBorrow);
        try {
            dataSource.init();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return dataSource;
    }

    @Bean
    public SchedulerFactoryBean wisdomSchedulerFactoryBean(JobFactory jobFactory) throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // this allows to update triggers in DB when updating settings in config file:
        // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job，这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 用于quartz集群,加载quartz数据源
        factory.setDataSource(dataSourceQuartz());
        factory.setJobFactory(jobFactory);
        // QuartzScheduler 延时启动，应用启动完10秒后 QuartzScheduler 再启动
        factory.setStartupDelay(10);
        // 用于quartz集群,加载quartz数据源配置
        factory.setQuartzProperties(quartzProperties());
        factory.setAutoStartup(true);
        factory.setApplicationContextSchedulerContextKey("applicationContext");
        return factory;
    }
}
